#include <sstream>
#include <cstdio>
#include <iostream>
#include "vl_utils.h"

using namespace VL;

/**
 * @Author: CimZzz
 * @Date: 2022-06-23 10:45:14
 * 
 * 私有构造方法
 */
VLUtils::VLUtils() {

}

/**
 * @Author: CimZzz
 * @Date: 2022-07-06 12:06:21
 * 
 * 转换为大写字符串
 * @param str 源字符串
 * @return 返回字符串
 */
std::string VLUtils::toUpperStr(const std::string& str) {
	size_t length = str.length();
	char destStr[length + 1];
	const char * srcStr = str.c_str();
	int diff = 'A' - 'a';
	for(int i = 0 ; i < length ; i ++) {
		char c = srcStr[i];
		if(c >= 'a' && c <= 'z') {
			destStr[i] = c + diff;
		} else {
			destStr[i] = c;
		}
	}
	destStr[length] = '\0';
	return std::string(destStr);
}

/**
 * @Author: CimZzz
 * @Date: 2022-07-06 12:06:21
 * 
 * 转换为小写字符串
 * @param str 源字符串
 * @return 返回字符串
 */
std::string VLUtils::toLowerStr(const std::string& str) {
	size_t length = str.length();
	char destStr[length + 1];
	const char * srcStr = str.c_str();
	int diff = 'a' - 'A';
	for(int i = 0 ; i < length ; i ++) {
		char c = srcStr[i];
		if(c >= 'A' && c <= 'Z') {
			destStr[i] = c + diff;
		} else {
			destStr[i] = c;
		}
	}
	destStr[length] = '\0';
	return std::string(destStr);
}

/**
 * @Author: CimZzz
 * @Date: 2022-07-04 19:18:42
 * 
 * 长整数转字符串
 * @param number 长整数
 * @return 转换后的字符串
 */
std::string VLUtils::long2str(int64_t number) {
	std::stringstream output;
	output << number;
	return output.str();
}

/**
 * @Author: CimZzz
 * @Date: 2022-06-23 10:46:25
 * 
 * 字符串转整数
 * @param str 字符串
 * @return 转换后的整数指针
 * 
 * @note 如果转换失败返回空指针
 */
std::shared_ptr<int> VLUtils::str2int(std::string& str) {
	bool isNegative = false;
	int number = 0;
	int begin = 0;
	// 抹除空格
	str.erase(0, str.find_first_not_of(" "));
	str.erase(str.find_last_not_of(" ") + 1);
	int length = str.length();
	if(length == 0) {
		return std::shared_ptr<int>(nullptr);
	}

	if(str.at(0) == '-') {
		// 负数
		isNegative = true;
		begin ++;
	}

	for(; begin < length ; begin ++) {
		char c = str.at(begin);
		if(c >= '0' && c <= '9') {
			number *= 10;
			number += c - '0';
			continue;
		}
		return std::shared_ptr<int>(nullptr);
	}

	return std::shared_ptr<int>(new int(number));
}

/**
 * @Author: CimZzz
 * @Date: 2022-06-27 18:04:11
 * 
 * 字符串转长整数
 * @param str 字符串
 * @return 转换后的长整数指针
 * 
 * @note 如果转换失败返回空指针
 */
std::shared_ptr<int64_t> VLUtils::str2long(std::string& str) {
	bool isNegative = false;
	int64_t number = 0;
	int begin = 0;
	// 抹除空格
	str.erase(0, str.find_first_not_of(" "));
	str.erase(str.find_last_not_of(" ") + 1);
	int length = str.length();
	if(length == 0) {
		return std::shared_ptr<int64_t>(nullptr);
	}

	if(str.at(0) == '-') {
		// 负数
		isNegative = true;
		begin ++;
	}

	for(; begin < length ; begin ++) {
		char c = str.at(begin);
		if(c >= '0' && c <= '9') {
			number *= 10;
			number += c - '0';
			continue;
		}
		return std::shared_ptr<int64_t>(nullptr);
	}

	return std::shared_ptr<int64_t>(new int64_t(number));
}

/**
 * @Author: CimZzz
 * @Date: 2022-09-08 14:28:12
 * 
 * 获取终端选择项
 * 
 * @param select 选择列表数据
 * 
 * @return 已选择数据
 */
VLSelectResult VLUtils::select(const VLSelectList& select) {
	std::vector<VLSelectItem> otherItemList;
	return VLUtils::select(select, otherItemList);
}

/**
 * @Author: CimZzz
 * @Date: 2022-10-20 17:55:53
 * 
 * 获取终端选择项
 * 
 * @param select 选择列表数据
 * @param otherItemList 其他列表选项
 * 
 * @return 已选择数据
 */
VLSelectResult VLUtils::select(const VLSelectList& select, const std::vector<VLSelectItem>& otherItemList) {
	auto list = select.items;
	int curPage = 0;
	int maxPage = list.size() / select.perpageCount + (list.size() % select.perpageCount == 0 ? 0 : 1) - 1;
	bool isRunning = true;
	std::string line;
	while(isRunning) {
		printf("%s\n", select.title.c_str());
		printf("\n");
		auto iter = list.begin() + curPage * select.perpageCount;
		// 打印列表
		int idx = 1;
		for(; idx <= select.perpageCount && iter != list.end() ; idx ++, iter ++) {
			printf("%d. %-15s: %s\n", idx, iter->name.c_str(), iter->info.c_str());
		}
		printf("page: %d/%d\n", curPage + 1, maxPage + 1);

		for(auto otherIter = otherItemList.begin() ; otherIter != otherItemList.end() ; otherIter ++) {
			printf("\n%s: %s", otherIter->name.c_str(), otherIter->info.c_str());
		}
		printf("\n\nn: next page");
		printf("\np: previous page");
		printf("\nq: exit select");
		printf("\n\nselect option number: ");
		
		std::getline(std::cin, line);

		line.erase(0, line.find_first_not_of(' '));
		line.erase(line.find_last_not_of(' ') + 1);
		if(line.size() == 1) {
			if(line.at(0) == 'q') {
				return VLSelectResult {
					.isNull = true,
					.name = "",
					.isOtherItem = false,
					.ptr = std::shared_ptr<void>(nullptr)
				};
			} else if(line.at(0) == 'n') {
				// 下一页
				if(curPage < maxPage) {
					// 未达到最后一页
					curPage ++;
				}
				continue;
			} if(line.at(0) == 'p') {
				// 上一页
				if(curPage > 0) {
					// 未达到第一页
					curPage --;
				}
				continue;
			}
			for(auto otherIter = otherItemList.begin() ; otherIter != otherItemList.end() ; otherIter ++) {
				if(line.at(0) == otherIter->name.at(0)) {
					return VLSelectResult {
						.isNull = false,
						.name = otherIter->name,
						.isOtherItem = true,
						.ptr = otherIter->ptr
					};
				}
			}
		}
		// 尝试转化为数字
		auto numberPtr = VLUtils::str2int(line);
		if(numberPtr.get() != nullptr) {
			auto selectNumber = *numberPtr;
			if(selectNumber < 1 || selectNumber > idx) {
				// 超过边界
				continue;
			}

			// 找到对应的数据项
			iter = list.begin() + curPage * select.perpageCount + (selectNumber - 1);
			return VLSelectResult {
				.isNull = false,
				.name = iter->name,
				.isOtherItem = false,
				.ptr = iter->ptr
			};
		}
	}

	return VLSelectResult {
		.isNull = true,
		.name = "",
		.isOtherItem = false,
		.ptr = std::shared_ptr<void>(nullptr)
	};
}

/**
 * @Author: CimZzz
 * @Date: 2022-09-13 11:56:53
 * 
 * 获取终端 Y/N 项
 * 
 * @param str 描述文本
 * @param defaultValue 缺省值
 * 
 * @return 如果为 Y 则返回 true
 */
bool VLUtils::askFor(const char* str, bool defaultValue) {
	bool isRunning = true;
	std::string line;
	while(isRunning) {
		printf("\n%s [Yy/Nn](default is %s):", str, (defaultValue ? "y" : "n"));
		std::getline(std::cin, line);
		if(line.empty()) {
			break;
		}
		if(line == "y" || line == "Y" || line == "yes" || line == "YES") {
			return true;
		}
		if(line == "n" || line == "N" || line == "no" || line == "NO") {
			return false;
		}
	}

	return defaultValue;
}